package socket.util;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import io.reactivex.schedulers.Schedulers;
import utils.ClickHelper;

/**
 * Created by bpb on 2019/8/7
 * 说明：
 */
public class SLog {

    private static SLog plcLog;

    private boolean open = true;


    private ClickHelper checkFileHelper = new ClickHelper(1000 * 60 * 30);//半小时允许检查一次

    private HashMap<String, String> logPaths = new HashMap<>();

    private String defaultFile = null;
    ArrayList<String> retFilePaths = new ArrayList<>();


    public static SLog getInstance() {
        if (plcLog == null) {
            synchronized (SLog.class) {
                if (plcLog == null) {
                    plcLog = new SLog();
                }
            }
        }
        return plcLog;
    }


    public void initLogFile(String file, String dir) {
        defaultFile = file;
        SimpleDateFormat sdf = new SimpleDateFormat("MM_dd", Locale.CHINA);
        String fileName = "SLog_" + sdf.format(new Date()) + file;
        String logFilePath;
        synchronized (SLog.class) {
            if (dir == null) {
                dir = "./log/";
            } else {
                dir = dir + "/log/";
            }

            mkDir(dir);

            logFilePath = dir + fileName + ".txt";
            File logFile = new File(logFilePath);
            if (!logFile.exists()) {
                try {
                    logFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (logPaths.containsKey(file)) {
                String oldFileName = logPaths.get(file);
                if (logFilePath.equals(oldFileName)) {
                    return;
                }
            }

            logPaths.put(file, logFilePath);

            File logFileParent = logFile.getParentFile();
            retFilePaths.clear();
            for (File log : logFileParent.listFiles()) {
                String name = log.getName();
                if (name.length() > 2) {
                    retFilePaths.add(log.getAbsolutePath());
                }
            }
        }
        //考虑到网络时间没校准的时候
        checkAndDelLog(logFilePath);
    }

    private void checkAndDelLog(final String logFilePath) {
        File logFile = (new File(logFilePath)).getParentFile();
        long current = System.currentTimeMillis();
        long checkTime = getEffectiveTime();
        //这么做是为了确保一下时间是准的网络时间
        if (current > checkTime) {
            for (File log : logFile.listFiles()) {
                String name = log.getName();
                if (name.startsWith("SLog_")) {
                    try {
                        if (current - log.lastModified() > 2592000000L) { // 30天前的日志， 要删除
//                    if (current - log.lastModified() > 172800000) { // 2天前的日志， 要删除
                            e_s("bpb", "删除 " + name + " = " + log.delete());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            Schedulers.io().scheduleDirect(new Runnable() {
                @Override
                public void run() {
                    checkAndDelLog(logFilePath);
                }
            }, 30, TimeUnit.SECONDS);
        }
    }


    private void internalSaveLog(String file, String tag, String msg) {
        if(defaultFile == null){
            return;
        }
        if (!open) {
            return;
        }
        if (checkFileHelper.canClick()) {
            initLogFile("", null);
        }
        String filePath = logPaths.get(file);
        if (filePath == null) {
            filePath = logPaths.get(defaultFile);
        }
        if (filePath != null&&filePath.length()>0) {
            try {
           //     2021-09-26 15:05:39.714 6218-6251/
                FileOutputStream fileOutputStream = new FileOutputStream(filePath, true);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.CHINA);
                byte[] bytes = (sdf.format(new Date()) +" " +"/"+ tag + ":" + msg + "\n").getBytes();
                fileOutputStream.write(bytes);
                fileOutputStream.flush();
                fileOutputStream.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       System.out.println(msg);
    }

    /**
     * 打印日志并保存到文件
     *
     * @param tag 日志标签
     * @param msg 日志内容
     */
    public void e_s(String tag, String msg) {
        e_s("", tag, msg);
    }
    public void e_s(String msg) {
        e_s("", ":", msg);
    }
    public void e_s(String file, String tag, String msg) {
        if (msg.length() > 4000) {
            for (int i = 0; i < msg.length(); i += 4000) {
                if (i + 4000 < msg.length())
                    internalSaveLog(file, tag, msg.substring(i, i + 4000));
                else
                    internalSaveLog(file, tag, msg.substring(i, msg.length()));
            }
        } else {
            //直接打印
            internalSaveLog(file, tag, msg);
        }
    }


    /**
     * 创建当前目录的文件夹
     */
    private void mkDir(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 删除当前日志
     */
    public void delectLogFile() {
        delectLogFile("");
    }

    public void delectLogFile(String file) {
        String logFilePath = logPaths.get(file);
        if (logFilePath != null) {
            synchronized (SLog.class) {
                File f = new File(logFilePath);
                f.delete();
            }
        }
    }

    public String e_s(String tag, Exception ex) {
        try {
            StringBuilder stringBuilder = new StringBuilder();
            StackTraceElement[] stackTraceElements = ex.getStackTrace();
            for (StackTraceElement element : stackTraceElements) {
                stringBuilder.append("\n" + element.toString());
            }
            e_s(tag, stringBuilder.toString());
            return stringBuilder.toString();
        } catch (Exception e) {
        }
        return "";
    }

    public String e_s(String tag, Throwable ex) {
        try {
            StringBuilder stringBuilder = new StringBuilder();
            StackTraceElement[] stackTraceElements = ex.getStackTrace();
            for (StackTraceElement element : stackTraceElements) {
                stringBuilder.append("\n" + element.toString());
            }
            e_s(tag, stringBuilder.toString());
            return stringBuilder.toString();
        } catch (Exception e) {
        }
        return "";
    }

    public void printCallerStracks() {
        e_s("Stack", getCallers());
    }

    public static String getCallers() {
        final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
        StringBuilder stringBuilder = new StringBuilder();
        try {
            for (int i = 4; i < 10; i++) {
                stringBuilder.append("\n" + "class:" + callStack[i].getClassName() + " line:" + callStack[i].getLineNumber() + ":" + callStack[i].getMethodName());
            }
        } catch (Exception e) {
        }
        return stringBuilder.toString();
    }

    public static long getEffectiveTime() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");// HH:mm:ss
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        try {
            return simpleDateFormat.parse("2021-01-01").getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public ArrayList<String> getLogFilePaths() {
        return retFilePaths;
    }
}
